package com.xci.sys.service;

import com.xci.core.base.PrimaryKeyValue;
import com.xci.core.base.RestMessage;
import com.xci.core.exceptions.AppException;
import com.xci.core.helper.Helper;
import com.xci.core.annotation.Log;
import com.xci.core.annotation.Valid;
import com.xci.core.internal.*;
import com.xci.core.base.BaseService;
import com.xci.core.web.TreeNode;
import com.xci.sys.dao.DicCategoryDao;
import com.xci.sys.dao.DicDao;
import com.xci.sys.entity.SysDic;
import com.xci.sys.entity.SysDicCategory;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.cache.Cache;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;

/**
 * 字典类型服务
 */
@Service
public class DicCategoryService extends BaseService {
    @Resource
    private DicCategoryDao dicCategoryDao;//字典类型数据层对象
    @Resource
    private DicDao dicDao;//字典数据层对象
    @Resource
    private Cache dicCache;//字典缓存对象

    /**
     * 新建字典类型
     * @param entity 字典类型对象
     */
    @Log(module = Const.Module.Dic, msg = "新建字典类型")
    @Transactional(rollbackFor = Exception.class)
    public RestMessage insert(@Valid SysDicCategory entity) {
        return save(entity,true);
    }

    /**
     * 修改字典类型
     * @param entity 字典类型对象
     */
    @Log(module = Const.Module.Dic, msg = "修改字典类型")
    @Transactional(rollbackFor = Exception.class)
    public RestMessage update(@Valid SysDicCategory entity) {
        return save(entity,false);
    }

    /**
     * 批量修改字段值
     * @param keyValues 字段值集合
     */
    @Log(module = Const.Module.Dic, msg = "批量更新字段值")
    @Transactional(rollbackFor = Exception.class)
    public RestMessage batchUpdate(List<PrimaryKeyValue> keyValues) {
        return batchUpdateParent(keyValues, new BatchUpdateCallback() {
            @Override
            public void updateParentId(String id, String parentId) {
                dicCategoryDao.updateParentId(id, parentId);
            }

            @Override
            public void updatePath(String id, String path) {
                dicCategoryDao.updatePath(id, path);
            }
        });
    }

    /**
     * 删除字典类型
     * @param ids 字典类型主键字符串,多个逗号隔开,该分类下面的所有字典项都会被删除
     */
    @Log(module = Const.Module.Dic, msg = "删除字典类型")
    @Transactional(rollbackFor = Exception.class)
    public RestMessage delete(@NotBlank(message = "请指定字典类型主键多个逗号隔开") String ids) {
        String[] idList = Helper.splitToArray(ids);
        for(String id : idList) {
            SysDicCategory old = dicCategoryDao.selectById(id);
            if(old == null) throw new AppException(Helper.format("无效的字典类型主键:[{}]",id));

            dicCategoryDao.delete(id);
            dicDao.deleteByCode(old.getCode()); //移除所有子项
            dicCache.evict(old.getCode());      //移除缓存
        }
        return RestMessage.success();
    }

    /**
     * 检查字典类型编码唯一性
     * @param code 字典类型编码
     * @return 如果存在返回true, 否则返回false
     */
    public Boolean existByCode(@NotBlank(message = "请指定字典类型编码") String code){
        return dicCategoryDao.existByCode(code, null);
    }

    /**
     * 查询单个字典类型
     * @param id 字典类型主键
     * @return 字典类型
     */
    public SysDicCategory selectById(@NotBlank(message = "请指定字典类型主键") String id){
        return dicCategoryDao.selectById(id);
    }

    /**
     * 查询单个字典类型对象
     * @param code 字典类型编码
     * @return 返回字典类型对象
     */
    public SysDicCategory selectByCode(@NotBlank(message = "请指定字典类型编码") String code) {
        return dicCategoryDao.selectByCode(code);
    }

    /**
     * 查询字典类型列表
     * @return 返回字典类型列表
     */
    public List<SysDicCategory> selectList() {
        return dicCategoryDao.selectList();
    }

    /**
     * 保存字典类型
     * @param entity 字典类型对象
     * @param created 是否新建
     */
    private RestMessage save(SysDicCategory entity, boolean created) {
        //自动添加主键
        if(created && Helper.isBlank(entity.getId())) {
            entity.setId(Helper.nextIdStr());
        }

        //字典类型编码唯一性验证
        if(dicCategoryDao.existByCode(entity.getCode(), created ? null : entity.getId())) {
            String msg = Helper.format("字典类型编码[{}]已经存在", entity.getCode());
            return RestMessage.fail(msg);
        }

        if(created) {// 新建
            Integer childCount = dicCategoryDao.selectChildCount(entity.getParentId());
            entity.setPath(childCount);
            dicCategoryDao.insert(entity);
        } else {//修改
            SysDicCategory old = dicCategoryDao.selectById(entity.getId());
            dicCategoryDao.update(entity);
            //当类型编码发生变化时,更新字典项的类型编码
            if(!old.getCode().equals(entity.getCode())) {
                dicDao.updateCode(old.getCode(), entity.getCode());
            }
            dicCache.evict(old.getCode());
        }
        return RestMessage.success();
    }

    /**
     * 转为节点列表
     *
     * @param models 模型列表
     */
    public List<TreeNode> convertToNodeList(List<SysDicCategory> models) {
        List<TreeNode> nodes = new ArrayList<>();
        if (ObjectUtils.isEmpty(models)) {
            return nodes;
        }
        for (var item : models) {
            boolean hasChild = models.stream().anyMatch(p -> p.getParentId().equals(item.getId()));
            TreeNode node = new TreeNode();
            node.setId(item.getId());
            node.setPid(item.getParentId());
            node.setText(item.getName());
            node.setSpell(Helper.getSpell(item.getName()));
            node.setLeaf(hasChild ? 0 : 1);
            nodes.add(node);
        }
        return nodes;
    }
}